<template>
  <div class="drag-rules" :style="dragStyle">
    <div class="origin" ref="o_ref" v-if="data.length > 0">
      <div class="origin-item"
           v-for="(item, index) in data"
           :key="index" draggable="true"
           @dragstart="handleDragStart(item, $event)"
           @dragend="handleDragEnd">{{item.label}}</div>
    </div>

    <div class="title" v-if="data.length > 0">使用方式：从上方拖放内容, 计算区域为从左向右计算</div>

    <div class="result"
         @drop="handleDrop"
         @dragover="handleDragOver" v-if="data.length > 0"
         @dragenter="handleDragEnter"
         @dragleave="handleDragLeave" ref="result_ref">
      <div class="result-item"
           v-for="(res, index) in express"
           :key="index" :style="res.type === -1 ? { color: '#999'} : rColor"
           :class="{'size-seat': res.type === -1}"
           :data-set="index"
           :data-item="JSON.stringify(res)" :ref="`ret_${index}_ref`"
           @dragover="handleDragOver"
           @dragenter="handleDragEnter">
        {{res.label}}<i class="close" @click.stop="handleDelExpress(res, index)" v-if="res.type !== -1">×</i>
      </div>
      <div class="empty" v-if="express.length === 0" @dragenter="handleDragEnter">请拖放到此处</div>
    </div>

    <div class="show" v-if="express.length > 0 && data.length > 0">
      <div>计算公式：</div>
      <ul>
        <li v-for="(o, index) in express" :key="index">{{o.label}}</li>
      </ul>
    </div>

    <div class="no-data" v-if="data.length === 0">数据为空</div>
  </div>
</template>

<script>
/* eslint-disable */
export default {
  name: "DragRules",
  data() {
    return {
      express: [],
      positions: {},
      isEnter: false,
      dragItem: {},
      dropCopy: {index: -1},
      canCopy: true,
      updateIng: false
    }
  },
  computed: {
    dragStyle() {
      let res = {}
      let width = typeof this.width === 'string' ? this.width : this.width + 'px'
      let height = typeof this.height === 'string' ? this.height : this.height + 'px'
      res = {
        width: width,
        height: height
      }
      if (this.data.length === 0) {
        res.background = "#fff"
        res.padding = "0"
      }
      return res
    },
    rColor() {
      return {
        color: this.color
      }
    }
  },
  props: {
    data: {
      type: Array,
      default() {
        return []
      }
    },
    width: {
      type: [String, Number],
      default: 'auto'
    },
    height: {
      type: [String, Number],
      default: 'auto'
    },
    color: {
      type: String,
      default: '#409eff'
    }
  },
  methods: {
    handleDrop(event) {
      let data = event.dataTransfer.getData('info')
      try {
        let cIndex = this.dropCopy.index
        let result = []
        this.express.forEach((item, key) => {
          if (key === cIndex) {
            result.push(JSON.parse(data))
          } else {
            result.push(item)
          }
        })
        this.express = result
        this.dropCopy = {}
      }catch (err) {
        console.log(err)
      }
      this.updatePositions()
      event.preventDefault()
    },
    getCopyItem(index, position) {
      let item = { type: -1, label: this.dragItem.label, index, position }
      this.dropCopy = item
      return item
    },
    delCopyItem() {
      if (this.dropCopy.index >= 0 ) {
        this.express.splice(this.dropCopy.index, 1)
        this.dropCopy = {}
        this.updatePositions()
      }
    },
    handleDragOver(event) {
      if (this.isEmpty() === 0) {
        if (this.dropCopy.index !== 0 && ( !this.dropCopy.index || this.dropCopy.index < 0 ) ) {
          this.express.push(this.getCopyItem(0))
          this.updatePositions()
        }
      } else {
        if (!this.updateIng) {
          this.handleExePosition(event)
        }
      }
      event.preventDefault()
    },
    handleExePosition(event) {
      let obj = this.getPosition(event.screenX, event.screenY)
      if (typeof obj.then === 'function') {
        obj.then(() => {
          let { index, type } = this.getPosition(event.screenX, event.screenY)
          this.updateIng = false
          if (index >= 0) {
            let tmp = this.getCopyItem(type === 'right' ? index + 1 : index, type)
            this.addExpress(index, tmp, type)
          }
        })
      } else {
        let { index, type } = obj
        this.updateIng = false
        if (index >= 0) {
          let tmp = this.getCopyItem(type === 'right' ? index + 1 : index, type)
          this.addExpress(index, tmp, type)
        }
      }
    },
    handleDragStart(item, event) {
      this.dragItem = item
      event.dataTransfer.setData('info', JSON.stringify(item))
    },
    handleDelExpress(data, index) {
      this.express.splice(index, 1)
      this.updatePositions()
    },
    handleDragEnter($event) {
      this.isEnter = true
      $event.preventDefault()
      $event.stopPropagation()
    },
    handleDragLeave($event) {
      $event.stopPropagation()
      $event.preventDefault()
      let fromEl = $event.fromElement
      if (!fromEl) return
      let className = fromEl.getAttribute('class')
      if (className && className.indexOf('result-item') >= 0) return
      if (className === 'result') return
      this.isEnter = false
    },
    handleDragEnd() {
      this.isEnter = false
      this.dragItem = {}
      this.delCopyItem()
    },
    getPosition(left, top) {
      this.updateIng = true
      let result = -1, type = ''
      for (let o in this.positions) {
        let tmp = this.positions[o]
        if (tmp.type === -1) continue
        let max = tmp.left + tmp.width
        let min = tmp.left
        let md = tmp.left + (tmp.width / 2)
        let maxTop = tmp.top + tmp.height
        let minTop = tmp.top
        console.log('top=', top, 'minTop = ', minTop, 'maxTop =', maxTop)
        if (left > min && left < max && top > minTop && top < maxTop ) {
          result = o * 1
          if (left >= md) {
            type = 'right'
          } else {
            type = 'left'
          }
        }
      }

      if ( this.dropCopy.index >= 0) {
        if (this.dropCopy.index !== result ) {
          this.delCopyItem()
          return this.$nextTick()
        } else {
          return { index: -1, type: ''}
        }
      } else {
        return { index: result, type}
      }
    },
    addExpress(index, item, type) {
      let result = []
      this.express.forEach((data, key) => {
        if (key === index) {
          switch (type) {
            case 'left':
              result.push(item)
              result.push(data)
              break
            case 'right':
              result.push(data)
              result.push(item)
              break
          }
        } else {
          result.push(data)
        }
      })
      this.express = result
      this.updatePositions()
    },
    isEmpty() {
      let index = 0
      this.express.forEach(item => {
        if (item.type !== -1) {
          index++
        }
      })
      return index
    },
    updatePositions() {
      this.$nextTick(() => {
        this.express.forEach((item ,index) => {
          let key = `ret_${index}_ref`
          let ref = this.$refs[key]
          if (Array.isArray(ref)) {
            let el = ref[0]
            let tmp = el.getBoundingClientRect()
            this.positions[`${index}`] = {
              ...item,
              left: tmp.left,
              top: tmp.top,
              right: tmp.right,
              bottom: tmp.bottom,
              width: tmp.width,
              height: tmp.height
            }
          }
        })
      })
    },
    handleEmptyExpress() {
      let result = true
      for (let i = 0; i < this.express.length; i++) {
        if (this.express[i].type !== -1) {
          result = false
          break
        }
      }
      return result
    }
  }
}
</script>

<style scoped lang="scss">
div.drag-rules{
  background: #f5f5f7;
  padding: 20px 0 0 0;
  border: 1px solid #eee;
  font-size: 14px;
  line-height: 1;
  position: relative;
  ul {
    list-style: none;
  }
  & > div.origin{
    padding: 0 20px;
    display: flex;
    flex-wrap: wrap;
    & > div.origin-item{
      padding: 10px 15px;
      border: 1px solid #eee;
      background: #fff;
      border-radius: 4px;
      margin-right: 10px;
      margin-bottom: 10px;
      user-select: none;
    }
  }

  & > div.title{
    background: #fff;
    padding: 10px 20px;
    display: flex;
    justify-content: flex-start;
    color: #999;
    font-size: 16px;
  }

  & > div.result{
    padding: 10px 20px;
    display: flex;
    justify-content: flex-start;
    align-items: center;
    flex-wrap: wrap;
    width: 100%;
    min-height: 100px;
    & > div.result-item{
      user-select: none;
      padding: 10px 20px;
      border: 1px solid #eee;
      background: #fff;
      border-radius: 4px;
      margin-right: 10px;
      margin-bottom: 10px;
      position: relative;
      & > i.close{
        display: block;
        position: absolute;
        top: 0;
        right: 0;
        font-size: 18px;
        cursor: pointer;
        font-style: normal;
      }

      &.size-seat{
        border: 1px dashed #eee;
        opacity: .5;
        color: #666;
      }
    }

    & > div.empty{
      padding: 30px 0;
      display: flex;
      justify-content: center;
      width: 100%;
      font-size: 20px;
      color: #999;
      user-select: none;
    }
  }

  & > div.show{
    display: flex;
    background: #fff;
    padding: 10px 20px;
    user-select: none;
    & > div{
      white-space: nowrap;
    }
    & > ul{
      display: flex;
      flex-wrap: wrap;
      & > li{
        margin-right: 7px;
        color: #222;
        font-weight: bold;
        font-size: 14px;
        margin-bottom: 7px;
      }
    }
  }

  div.no-data{
    height: 60px;
    display: flex;
    justify-content: center;
    align-items: center;
    user-select: none;
    font-size: 24px;
    color: #999;
  }
}
</style>
